Skip to content

Spring Task

在企业级开发中,我们经常需要处理一些“定时”或“周期性”的任务,比如每天凌晨生成报表、每隔 1 小时清理一次缓存或者每分钟检查一次支付状态。Spring Task 就是为此设计的轻量级解决方案。


1. 什么是 Spring Task?

Spring Task 是 Spring Framework 自 3.0 版本起引入的任务调度模块。它提供了一套简单、注解驱动的方式来实现定时任务,无需引入像 Quartz 这样复杂的外部框架,就能满足绝大多数单机应用的调度需求。

核心优势:

  • 配置简单:只需几个注解即可搞定,不需要复杂的 XML 或对象配置。
  • 无需依赖:作为 Spring 的核心模块,不需要引入额外的 jar 包。
  • 支持 Cron 表达式:支持非常灵活的时间配置。

2. 核心注解

要让 Spring Task 跑起来,你只需要记住两个关键注解:

  1. @EnableScheduling:放在配置类或启动类上,表示开启定时任务功能。
  2. @Scheduled:放在具体的方法上,定义该任务的执行触发时机。

3. 任务触发方式

@Scheduled 注解中,有三种常见的执行频率设置方式:

A. fixedRate (固定速率)

任务开始执行后,每隔指定时间执行一次。

例子@Scheduled(fixedRate = 5000) —— 每 5 秒执行一次,不管上一次任务是否结束。

B. fixedDelay (固定延迟)

上一次任务结束后,经过指定时间再执行下一次。

例子@Scheduled(fixedDelay = 5000) —— 如果任务跑了 10 秒,结束后再等 5 秒才跑下一次。

C. cron (Cron 表达式)

最强大的方式,可以指定非常具体的时间点。注意: “日”“周” 两个字段不能同时指定具体数值,规定一个,另外一个就写"?"。

语法结构[秒] [分] [时] [日] [月] [周]

例子@Scheduled(cron = "0 0 2 * * ?") —— 每天凌晨 2:00 执行。


4. 快速上手代码示例

下面是一个简单的实现逻辑:

java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;

@Component
public class MyStaticTask {

    // 1. 每隔 10 秒执行一次
    @Scheduled(fixedRate = 10000)
    public void reportCurrentTime() {
        System.out.println("现在时间:" + LocalDateTime.now());
    }

    // 2. 每天凌晨 1 点清理日志
    @Scheduled(cron = "0 0 1 * * ?")
    public void cleanLogs() {
        System.out.println("清理日志任务开始...");
    }
}

5. 注意事项与局限性

虽然 Spring Task 很好用,但在使用时有两点需要注意:

  • 默认单线程执行:Spring Task 默认使用单线程池。这意味着如果你的任务 A 卡住了,任务 B 即使到了时间也无法执行。如果你有大量并发任务,建议配置 TaskScheduler 线程池。
  • 不支持分布式:Spring Task 是内存级的任务调度。如果你的应用部署了多台服务器(集群),每台机器都会在同一时间跑同一个任务。
    • 解决方法:如果是分布式环境,通常需要配合 Redis 分布式锁,或者改用 ShedLockXXL-JOB 等分布式调度平台。
  • Spring 坑:定时任务方法必须是 public 的,且所在的类必须被 @Component@Service 扫描到,否则任务根本不会被触发。